package io.github.iogogogo.commons.support;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * Created by tao.zeng on 2024/11/7.
 */
public class JacksonConfig {

    private enum SingletonEnum {
        INSTANCE;

        private final JacksonConfig singletonPattern;

        SingletonEnum() {
            singletonPattern = new JacksonConfig();
        }

        public JacksonConfig getInstance() {
            return singletonPattern;
        }
    }

    /**
     * 获取Jackson配置的单例实例
     * <p>
     * 本方法利用SingletonEnum枚举类的INSTANCE枚举实例来实现单例模式
     * 这种方式确保了线程安全，并且避免了类加载器的问题，是实现单例的一种简洁高效的方式
     *
     * @return JacksonConfig的单例实例
     */
    public static JacksonConfig getInstance() {
        return SingletonEnum.INSTANCE.getInstance();
    }

    /**
     * 构建并配置一个ObjectMapper实例，用于JSON序列化和反序列化
     * 该方法主要进行了一些自定义配置，以满足特定的序列化和反序列化需求
     *
     * @return 配置好的ObjectMapper实例
     */
    public ObjectMapper buildObjectMapper() {
        // 创建一个ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        // Java8 日期序列化反序列化处理
        // 注册JavaTimeModule模块以支持Java8日期时间API的序列化和反序列化
        objectMapper.registerModule(new JavaTimeModule());
        // 禁用时间戳形式的日期写法，确保日期以ISO-8601日期格式写入
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 配置反序列化特性，忽略未知属性，避免反序列化失败
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 使用BigDecimal来反序列化浮点数，确保精度准确
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
        // 配置生成特征，以纯文本形式写入BigDecimal，避免科学计数法
        objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        // 允许控制字符在JSON字符串中出现，适应某些特殊场景
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 代码配置输出格式，未启用
        // .configure(com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT, true)
        // 重新配置浮点数反序列化方式，覆盖之前配置
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, false);

        // 创建一个自定义模块，用于注册自定义序列化器和反序列化器
        SimpleModule simpleModule = new SimpleModule();

        /*
         *  将Long,BigInteger,BigDecimal序列化的时候,转化为String
         *  这是为了避免精度损失，特别是在处理大数值时
         */
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);

        // 注册自定义模块到ObjectMapper实例
        objectMapper.registerModule(simpleModule);

        // 返回配置好的ObjectMapper实例
        return objectMapper;
    }
}
